package annotool.select;

/*
  parameters for mRMR:

  - threshold: a float number of the discretization threshold; non-specifying this parameter means no discretizaton (i.e. data is already integer); 0 to make binarization.

  - method: either \"MID\" or \"MIQ\" (Capital case), default is MID

  - number of features: A natural number. efault is 50.

  - max number of samples: a natural number, default is 1000. Note that if you don't have or don't need big memory, set this value small, as this program will use this value to pre-allocate memory in data file reading.

  - max number of variables/attibutes in data>   a natural number, default is 10000. Note that if you don't have or don't need big memory, set this value small, as this program will use this value to pre-allocate memory in data file reading.

    From the C version:
    ("\nUsage: mrmr -i <dataset> -t <threshold> [optional arguments]\n");
    ("\t -i <dataset>    .CSV file containing M rows and N columns, row - sample, column - variable/attribute.\n");
    ("\t -t <threshold> a float number of the discretization threshold; non-specifying this parameter means no discretizaton (i.e. data is already integer); 0 to make binarization.\n");
    ("\t -n <number of features>   a natural number, default is 50.\n");
    ("\t -m <selection method>    either \"MID\" or \"MIQ\" (Capital case), default is MID.\n");
    ("\t -s <MAX number of samples>   a natural number, default is 1000. Note that if you don't have or don't need big memory, set this value small, as this program will use this value to pre-allocate memory in data file reading.\n");
    ("\t -v <MAX number of variables/attibutes in data>   a natural number, default is 10000. Note that if you don't have or don't need big memory, set this value small, as this program will use this value to pre-allocate memory in data file reading.\n");
 */

public class mRMRFeatureSelector implements FeatureSelector
{

	// Loads the file mRMRNative.DLL at run-time
	static {
		System.loadLibrary("mRMRNative");
	}

	float[][] features;
	int[] targets;
	int length = 0;
	int dimension = 0;
	int numberofFeatures = 10;

	String method = annotool.Annotator.DEFAULT_MRMRTYPE; //Default is "mRMR-MIQ".

	public mRMRFeatureSelector(float[][] features, int[] targets, int length, int dimension, int numberofFeatures, String method, boolean discreteflag)
	{

		//discrete before mRMR selection
		this.features = features;
		this.targets = targets;
		this.length = length;
		this.dimension = dimension;
		this.numberofFeatures = numberofFeatures;
		this.method = method;
		if(discreteflag)
			discretize(features, length, dimension);

	}

	//Use the default method (MIQ)
	public mRMRFeatureSelector(float[][] features, int[] targets, int length, int dimension, int numberofFeatures, boolean discreteflag)
	{
		//discrete before mRMR selection
		this.features = features;
		this.targets = targets;
		this.length = length;
		this.dimension = dimension;
		this.numberofFeatures = numberofFeatures;
		if(discreteflag)
			discretize(features, length, dimension);

	}

	//return the selected features in vectors
	public float[][] selectFeatures()
	{
		int[] indices = mRMRSelection();
		//For debugging
		//int[] indices = {3675, 2474, 1303, 2450, 3896, 4998, 4927, 3777, 1321, 1475, 1376, 2623, 326, 2776, 4971 };

		float[][] selectedFeatures = new float[length][numberofFeatures];

		for(int i=0; i<length; i++)
			for(int j=0; j<numberofFeatures; j++)
			{
				//System.out.println("j: " + j + "feature index"+ indices[j]);
				selectedFeatures[i][j] = features[i][indices[j]];
			}

		return selectedFeatures;

	}

	//the one that calls the C native interface
	//return the column indices of the selected features
	protected int[] mRMRSelection()
	{

		//C++ mRMR takes 1D array
		float[] OneDfeatures = new float[length*dimension];
		for(int i=0; i< length; i++)
			for(int j=0; j< dimension; j++)
				OneDfeatures[i*dimension+j] = features[i][j];

		if (method.equalsIgnoreCase("mRMR-MIQ"))
			return mRMRNative.miq(OneDfeatures, targets, numberofFeatures, length, dimension);
		else if (method.equalsIgnoreCase("mRMR-MID"))
			return mRMRNative.mid(OneDfeatures, targets, numberofFeatures, length, dimension);
		//	   else
		//	   {
		//         throw new Exception("Unknown feature selector method.");
		//       }

		//by PHC, 081007
		else
			return null;

	}

	//discretize feature so that it only contains 3 values -1, 0, and +1,
	//called before mRMRfeature selection, if necessary.
	protected void discretize(float[][] features, int length, int dimension)
	{
		//   % discretwave= (sign(wavecoef-repmat(mean(wavecoef,1), size(wavecoef,1),1)));
	
        float sum = 0, mean = 0;
        for (int j=0; j< dimension; j++)
        {
  		  sum =0;
          for (int i =0; i<length; i++)
			   sum += features[i][j];
	      mean = sum/length;
          for (int i =0; i<length; i++)
          {
            //features[i][j] -= mean;	 
			
            if(features[i][j] > mean)
			     features[i][j] = 1;
			   else if(features[i][j] < mean)
			     features[i][j] = -1;
			   else
			       features[i][j] = 0;
	       
	     }
	   }
		/*
		   for(int i=0; i<length; i++)
		   {
		     for(int j=0; j<dimension; j++)
		      System.out.print(features[i][j]+"\t");
		     System.out.println();
	       }
	       */
	}
	
    private Integer[] getTargetList()
    {
		java.util.ArrayList<Integer> targetList = new java.util.ArrayList<Integer>();
		for (int i=0; i < targets.length; i++)
			if(!targetList.contains(targets[i]))
				targetList.add(targets[i]);
		
		Integer res[] = new Integer[targetList.size()];
		return targetList.toArray(res);
    }

}

